package com.enke.jpa.config;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.HashMap;

@Configuration
@EnableTransactionManagement // 开启事务
@EnableJpaRepositories(basePackages = { "com.enke" },
        entityManagerFactoryRef = "primaryEntityManagerFactory",
        transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryDataSourceConfig {
    /**
     * 指定 primary 数据源的 dataSource 配置
     *
     * @return primary 数据源配置
     */
    @Primary
    @Bean(name = "primaryDataSourceProperties")
    @ConfigurationProperties("spring.datasource.primary")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    /**
     * 可以选择不同的数据源，这⾥使⽤ HikariDataSource，创建数据源
     *
     * @param primaryDataSourceProperties
     *            数据源配置
     * @return primary 数据源
     */
    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.hikari.primary") // 配置
    // primary
    // 数据源所⽤的
    // hikari
    // 配置
    // key
    // 的前缀
    public DataSource dataSource(
            @Qualifier("primaryDataSourceProperties") DataSourceProperties primaryDataSourceProperties) {
        HikariDataSource dataSource = primaryDataSourceProperties.initializeDataSourceBuilder()
                .type(HikariDataSource.class).build();
        if (StringUtils.hasText(primaryDataSourceProperties.getName())) {
            dataSource.setPoolName(primaryDataSourceProperties.getName());
        }
        return dataSource;
    }

    /**
     * 配置 primary 数据源的 entityManagerFactory 命名为
     * primaryEntityManagerFactory，⽤来对实体进⾏⼀些操作
     *
     * @param builder
     *            构建器
     * @param primaryDataSource
     *            primary 数据源
     * @return primary 实体管理工厂
     */
    @Primary
    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
                                                                       @Qualifier("primaryDataSource") DataSource primaryDataSource) {
        final HashMap<String, Object> hibernateProperties = new HashMap<String, Object>();
        hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
        return builder.dataSource(primaryDataSource).properties(hibernateProperties)
                // primary 数据的实体所在的路径
                .packages("com.enke.jpa.domain")
                // persistenceUnit 的名字采⽤ primary
                .persistenceUnit("primary").build();
    }

    /**
     * 配置 primary 数据源的事务管理者，命名为 primaryTransactionManager 依赖
     * primaryEntityManagerFactory
     *
     * @param primaryEntityManagerFactory
     *            primary 实体管理工厂
     * @return primary 事务管理者
     */
    @Primary
    @Bean(name = "primaryTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("primaryEntityManagerFactory") EntityManagerFactory primaryEntityManagerFactory) {
        return new JpaTransactionManager(primaryEntityManagerFactory);
    }
}
